package com.hyt.it.ogt.kq.service.govData.service.kwgov.impl;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;

import javax.annotation.Resource;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import com.google.common.collect.Lists;
import com.hyt.core.base.BaseServiceImpl;
import com.hyt.core.util.UUIDUtils;
import com.hyt.it.ogt.cj.service.IProjectCollectInfoOptionService;
import com.hyt.it.ogt.cj.service.IProjectCollectInfoService;
import com.hyt.it.ogt.cj.service.IProjectImageStandardService;
import com.hyt.it.ogt.kq.common.bm.enums.BmAuditStatusEnum;
import com.hyt.it.ogt.kq.common.bm.enums.BmProjectAllowRefundEnum;
import com.hyt.it.ogt.kq.common.bm.enums.BmProjectNeedPayEnum;
import com.hyt.it.ogt.kq.common.bm.enums.BmProjectVerifyEnum;
import com.hyt.it.ogt.kq.common.bm.utils.ExecutorPoolUtil;
import com.hyt.it.ogt.kq.common.config.ConfigManager;
import com.hyt.it.ogt.kq.common.config.exception.KqException;
import com.hyt.it.ogt.kq.common.gov.constant.ResponseCode;
import com.hyt.it.ogt.kq.common.gov.utils.CacheKeyManager;
import com.hyt.it.ogt.kq.service.admission.ICandidateInfoService;
import com.hyt.it.ogt.kq.service.bm.model.entity.Project;
import com.hyt.it.ogt.kq.service.bm.service.IProjectService;
import com.hyt.it.ogt.kq.service.gov.den.PicCompressUtil;
import com.hyt.it.ogt.kq.service.gov.den.TencentCloudCosUtil;
import com.hyt.it.ogt.kq.service.gov.mapper.TaskMapper;
import com.hyt.it.ogt.kq.service.gov.model.entity.CustomArrange;
import com.hyt.it.ogt.kq.service.gov.model.entity.Task;
import com.hyt.it.ogt.kq.service.gov.model.entity.Time;
import com.hyt.it.ogt.kq.service.gov.service.ICandidatePhotoService;
import com.hyt.it.ogt.kq.service.gov.service.ICandidateService;
import com.hyt.it.ogt.kq.service.gov.service.ICandidateSubjectService;
import com.hyt.it.ogt.kq.service.gov.service.ICustomArrangeService;
import com.hyt.it.ogt.kq.service.gov.service.ISubjectService;
import com.hyt.it.ogt.kq.service.gov.service.ITaskCandidateAreaService;
import com.hyt.it.ogt.kq.service.gov.service.ITaskOverviewService;
import com.hyt.it.ogt.kq.service.gov.service.ITaskService;
import com.hyt.it.ogt.kq.service.gov.service.ITimeService;
import com.hyt.it.ogt.kq.service.govData.service.kwgov.IKwBingService;
import com.hyt.it.ogt.kq.service.model.entity.Candidate;
import com.hyt.it.ogt.kq.service.model.entity.CandidatePhoto;
import com.hyt.it.ogt.kq.service.model.entity.CandidateSubject;
import com.hyt.it.ogt.kq.service.model.entity.Subject;
import com.hyt.it.ogt.kq.service.model.entity.TaskCandidateArea;
import com.hyt.it.ogt.kq.service.model.entity.admission.CandidateInfo;
import com.hyt.it.ogt.kq.service.model.vo.candidateSubject.BmTaskData;

import cn.hutool.core.collection.CollUtil;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Service
public class KwBingServiceImpl extends BaseServiceImpl<TaskMapper, Task> implements IKwBingService {
	
    @Resource
	private ITaskService iTaskService;
	@Resource
	private ITimeService iTimeService;
	@Resource
	private ISubjectService iSubjectService;
	@Resource
	private ICandidateService iCandidateService;
	@Resource
	private ICandidateSubjectService iCandidateSubjectService;
	@Resource
	private ICandidatePhotoService iCandidatePhotoService;
	@Resource
	private ITaskCandidateAreaService iTaskCandidateAreaService;
	@Resource
	private ITaskOverviewService iTaskOverviewService;
	@Resource
	private ICustomArrangeService iCustomArrangeService;
	@Resource
	private PicCompressUtil picCompressUtil;
	@Resource
    private RedisTemplate<String, Object>  redisTemplate;
	@Resource
	private ConfigManager configManager;
	@Resource
	ICandidateInfoService iCandidateInfoService;
	@Resource
	IProjectCollectInfoService iProjectCollectInfoService;
	@Resource
	IProjectCollectInfoOptionService iProjectCollectInfoOptionService;
	@Resource
	IProjectImageStandardService iProjectImageStandardService;
	@Resource
	private IProjectService projectService;


	@Override
	public void verifyBingCondition(String bmProjectId, String taskId) {
	    // 校验报名是否已经结束
	    Project bmProject = projectService.getById(bmProjectId);
	    // 如果报名不需要审核, 不需要缴费
	    if(BmProjectVerifyEnum.UNVERIFY.getVerifyStatus().equals(bmProject.getIsVerify()) && BmProjectNeedPayEnum.UNPAY.getPayStatus().equals(bmProject.getIsPay())) {
	        if(null != bmProject.getEndTime() && bmProject.getEndTime().isAfter(LocalDateTime.now())) {
	            throw new KqException(ResponseCode.ERROR_BMPROJECT_HAS_UNEND.getCode(), ResponseCode.ERROR_BMPROJECT_HAS_UNEND.getMsg());
	        }
	    }
	    // 如果报名不需要审核, 需要缴费
	    if(BmProjectVerifyEnum.UNVERIFY.getVerifyStatus().equals(bmProject.getIsVerify()) && BmProjectNeedPayEnum.PAY.getPayStatus().equals(bmProject.getIsPay())) {
	        // 如果允许退费
	        if(BmProjectAllowRefundEnum.ALLOW.getRefundStatus().equals(bmProject.getIsRefund())) {
	            if(null != bmProject.getRefuseTime() && bmProject.getRefuseTime().isAfter(LocalDateTime.now())) {
	                throw new KqException(ResponseCode.ERROR_BMPROJECT_HAS_UNEND.getCode(), ResponseCode.ERROR_BMPROJECT_HAS_UNEND.getMsg());
	            }
	        }
	        // 如果不允许退费
	        if(BmProjectAllowRefundEnum.UNALLOW.getRefundStatus().equals(bmProject.getIsRefund())) {
                if(null != bmProject.getPayEndTime() && bmProject.getPayEndTime().isAfter(LocalDateTime.now())) {
                    throw new KqException(ResponseCode.ERROR_BMPROJECT_HAS_UNEND.getCode(), ResponseCode.ERROR_BMPROJECT_HAS_UNEND.getMsg());
                }
            }
        }
	    // 如果报名需要审核, 需要缴费
        if(BmProjectVerifyEnum.VERIFY.getVerifyStatus().equals(bmProject.getIsVerify()) && BmProjectNeedPayEnum.PAY.getPayStatus().equals(bmProject.getIsPay())) {
            // 如果允许退费
            if(BmProjectAllowRefundEnum.ALLOW.getRefundStatus().equals(bmProject.getIsRefund())) {
                if(null != bmProject.getRefuseTime() && bmProject.getRefuseTime().isAfter(LocalDateTime.now())) {
                    throw new KqException(ResponseCode.ERROR_BMPROJECT_HAS_UNEND.getCode(), ResponseCode.ERROR_BMPROJECT_HAS_UNEND.getMsg());
                }
            }
            // 如果不允许退费
            if(BmProjectAllowRefundEnum.UNALLOW.getRefundStatus().equals(bmProject.getIsRefund())) {
                if(null != bmProject.getPayEndTime() && bmProject.getPayEndTime().isAfter(LocalDateTime.now())) {
                    throw new KqException(ResponseCode.ERROR_BMPROJECT_HAS_UNEND.getCode(), ResponseCode.ERROR_BMPROJECT_HAS_UNEND.getMsg());
                }
            }
        }
        // 如果报名需要审核, 不需要缴费
        if(BmProjectVerifyEnum.VERIFY.getVerifyStatus().equals(bmProject.getIsVerify()) && BmProjectNeedPayEnum.UNPAY.getPayStatus().equals(bmProject.getIsPay())) {
            if(null != bmProject.getAuditEndTime() && bmProject.getAuditEndTime().isAfter(LocalDateTime.now())) {
                throw new KqException(ResponseCode.ERROR_BMPROJECT_HAS_UNEND.getCode(), ResponseCode.ERROR_BMPROJECT_HAS_UNEND.getMsg());
            }
            if(null == bmProject.getAuditEndTime() && bmProject.getEndTime().isAfter(LocalDateTime.now())) {
                throw new KqException(ResponseCode.ERROR_BMPROJECT_HAS_UNEND.getCode(), ResponseCode.ERROR_BMPROJECT_HAS_UNEND.getMsg());
            }
        }
	    
	    
		// 2.校验数据锁定状态，锁定后不能绑定了。
		iTaskService.isLockDataThrowException(taskId);

		// 3.如果有科目数据不允许绑定
		Integer countSubject = iSubjectService.lambdaQuery().eq(Subject::getTaskId, taskId).eq(Subject::getDelFlag, false).count();
		if (countSubject > 0) {
			throw new KqException(ResponseCode.ERROR_BINDTASK_HAS_SUBJECT_DATA.getCode(), ResponseCode.ERROR_BINDTASK_HAS_SUBJECT_DATA.getMsg());
		}

		// 4.如果有批次数据不允许绑定
		Integer countTime = iTimeService.lambdaQuery().eq(Time::getTaskId, taskId).eq(Time::getDelFlag, false).count();
		if (countTime > 0) {
			throw new KqException(ResponseCode.ERROR_BINDTASK_HAS_TIME_DATA.getCode(), ResponseCode.ERROR_BINDTASK_HAS_TIME_DATA.getMsg());
		}

		// 5.如果有考生数据不允许绑定
		Integer countCandidate = iCandidateService.lambdaQuery().eq(Candidate::getTaskId, taskId).eq(Candidate::getDelFlag, false).count();
		if (countCandidate > 0) {
			throw new KqException(ResponseCode.ERROR_BINDTASK_HAS_CANDIDATE_DATA.getCode(), ResponseCode.ERROR_BINDTASK_HAS_CANDIDATE_DATA.getMsg());
		}
	}


	@Override
	public void bindBm(String taskId, String projectId, BmTaskData bmTaskData) throws Exception {
		String progressKey = CacheKeyManager.getBingingLockProgressKey(taskId);
		log.info("## 考试同步数据到考务库,{},{}", taskId, projectId);
		if(null == bmTaskData) {
			redisTemplate.opsForValue().set(progressKey, 100);
			return;
		}
		
		//删除原来的绑定数据
		removeBindData(taskId);
		
		redisTemplate.opsForValue().set(progressKey, 35);
		
		//更新kw_task表
		updateKwTask(taskId, projectId);
		
		redisTemplate.opsForValue().set(progressKey, 40);
		

		//插入kw_task_candidate_area表
		List<TaskCandidateArea> taskCandidateAreaList = bmTaskData.getTaskCandidateAreaList();
		if (taskCandidateAreaList != null && !taskCandidateAreaList.isEmpty()) {
			taskCandidateAreaList.stream().forEach(a -> a.setTaskId(taskId));
			iTaskOverviewService.assemblingAreaSave(taskCandidateAreaList);
		}
		int subjectCode = 1;
		//插入kw_subject表
		List<Subject> subjectList = bmTaskData.getSubjectList();
		List<Subject> kwSublists = new ArrayList<>();
		if (subjectList != null && !subjectList.isEmpty()) {
			for (Subject subject : subjectList) {
				Subject kwsubject = new Subject();
				BeanUtils.copyProperties(subject, kwsubject);
				kwsubject.setTaskId(taskId);
				subjectCode = subjectCode + 1;
				if(subjectCode <= 9){
					kwsubject.setCode("km00" + subjectCode);
				} else if (subjectCode <= 99){
					kwsubject.setCode("km0" + subjectCode);
				} else {
					kwsubject.setCode("km" + subjectCode);
				}
				//kwsubject.setCode(String.valueOf(subjectCode++));
				kwSublists.add(kwsubject);
			}
			iSubjectService.saveBatch(kwSublists);
		}
		
		redisTemplate.opsForValue().set(progressKey, 45);
		
		if(CollectionUtils.isEmpty(bmTaskData.getCandidateList())) {
			redisTemplate.opsForValue().set(progressKey, 100);
			return;
		}
		
		//报名科目id和政企考务科目id对应关系map
		Map<String, String> subjectIdMap = new HashMap<>(2);
		kwSublists.stream().forEach(s -> subjectIdMap.put(s.getBmSubjectId(), s.getId()));

		// 插入自定义准考证表
		List<CustomArrange> customArrangeList = new ArrayList<>();
		//插入kw_candidate表
		List<Candidate> candidateList = bmTaskData.getCandidateList();
		List<Candidate> kwcandidateList = new ArrayList<>();
		
		//报名考生id和政企考务考生id对应关系map
		Map<String, String> candidateIdMap = new HashMap<>(2);
				
		if (candidateList != null && !candidateList.isEmpty()) {
			for (Candidate bmcandidate : candidateList) {
				Candidate kwcandidate = new Candidate();
				BeanUtils.copyProperties(bmcandidate, kwcandidate);
				kwcandidateList.add(kwcandidate);
			}
			kwcandidateList.stream().forEach(c -> c.setTaskId(taskId));
			iCandidateService.saveBatch(kwcandidateList);
			redisTemplate.opsForValue().set(progressKey, 50);
			
			kwcandidateList.stream().forEach(item -> {
				candidateIdMap.put(item.getBmStudentId(), item.getId());

				if(StringUtils.isNotBlank(item.getAdmissionno())) {
					// 增加自定义准考证字段同步到考务
					CustomArrange customArrange = new CustomArrange();
					customArrange.setCandidateId(item.getId());
					customArrange.setTaskId(taskId);
					customArrange.setAdmissionNumber(item.getAdmissionno());
					customArrangeList.add(customArrange);
				}
			});

			if(!customArrangeList.isEmpty()) {
				iCustomArrangeService.saveBatch(customArrangeList);
			}
			redisTemplate.opsForValue().set(progressKey, 60);
		}
		
		// 插入kw_candidate_info表
		List<CandidateInfo> candidateInfoList = bmTaskData.getCandidateInfoList();
		if (CollUtil.isNotEmpty(candidateInfoList)) {
			candidateInfoList.stream()
					.forEach(data -> {
						String candidateId = candidateIdMap.get(data.getStudentId());
						data.setTaskId(taskId)
								.setCandidateId(candidateId)
                                .setId(UUIDUtils.newSortUUID());
					});
            iCandidateInfoService.saveBatch(candidateInfoList);
			log.debug("# 插入kw_candidate_info表：{}", CollUtil.size(candidateInfoList));
            redisTemplate.opsForValue().set(progressKey, 70);
		}

		//插入kw_candidate_subject表
		List<CandidateSubject> candidateSubjectList = bmTaskData.getCandidateSubjectList();
		if (candidateSubjectList != null && !candidateSubjectList.isEmpty()) {
			candidateSubjectList.stream().forEach(cs -> {
				// 设置taskid字段
				cs.setTaskId(taskId);
				// 替换科目id和考生id
				cs.setSubjectId(subjectIdMap.get(cs.getSubjectId()));
				// 设置考生id
				cs.setCandidateId(candidateIdMap.get(cs.getCandidateId()));
				if (cs.getAnswerType() == null) {
					//没有推送作答方式的情况下，为考生科目数据设置默认作答方式，保证编排能正常执行
					cs.setAnswerType(1);
				}
				if (cs.getLanguage() == null) {
					//没有推送语种的情况下，为考生科目数据设置默认语种，保证编排能正常执行
					cs.setLanguage(1);
				}
			});
			iCandidateSubjectService.saveBatch(candidateSubjectList);
			redisTemplate.opsForValue().set(progressKey, 80);
		}
		
		//插入kw_candidate_photo表
		List<CandidatePhoto> candidatePhotoList = bmTaskData.getCandidatePhotoList();
		if (CollectionUtils.isNotEmpty(candidatePhotoList)) {
			candidatePhotoList.forEach(cp -> {
				cp.setId(UUIDUtils.newSortUUID());
				cp.setTaskId(taskId);
				//替换考生id
				cp.setCandidateId(candidateIdMap.get(cp.getCandidateId()));
			});
			iCandidatePhotoService.saveBatch(candidatePhotoList);
			//压缩腾讯云COS照片
			log.info("## bindBm compressTencentCosPhoto start......");
			try {
//				this.compressTencentCosPhoto(candidatePhotoList, taskId, bmTaskData.getOfficeId());
				// 对考生图片分组异步提交，不阻塞进度
				List<List<CandidatePhoto>> partitionCandidatePhotoList = Lists.partition(candidatePhotoList, configManager.getCandidatePhotobatchsize());
				for (List<CandidatePhoto> list : partitionCandidatePhotoList) {
					this.compressTencentCosPhotoAsync(list, taskId, bmTaskData.getOfficeId());
				}
			} catch (Exception e) {
				log.error("## compressTencentCosPhoto error:{}", e);
			}
			log.info("## bindBm compressTencentCosPhoto end......");
			redisTemplate.opsForValue().set(progressKey, 85);
		}

		redisTemplate.opsForValue().set(progressKey, 100);
		log.info("## 考试同步数据到考务库结束,{},{}", taskId, projectId);
	}
	
	
	private void compressTencentCosPhotoAsync(List<CandidatePhoto> candidatePhotoList, String taskId, String officeId) throws Exception {
		// 开始同步数据
		ExecutorPoolUtil.getPoolTaskExecutor().submit(new Callable<List<CandidatePhoto>>() {
			@Override
			public List<CandidatePhoto> call() throws Exception {
				try {
					List<List<CandidatePhoto>> candidatePhotoPpartitions = Lists.partition(candidatePhotoList, 1000);
					for (List<CandidatePhoto> candidatePhotoPartitionTemp : candidatePhotoPpartitions) {
						if(CollectionUtils.isNotEmpty(candidatePhotoPartitionTemp)) {
							for (CandidatePhoto candidatePhotoTemp : candidatePhotoPartitionTemp) {
								//组装目标路径（存储规则：“根目录/任务编号/业务功能目录/具体的文件.xxx”）
								String rootPath = TencentCloudCosUtil.getPhotoRootPath(taskId);
								String targetPath = rootPath + candidatePhotoTemp.getName();
								 picCompressUtil.compressTencentCosPhoto(officeId,candidatePhotoTemp, targetPath);
							}
						}
						iCandidatePhotoService.saveOrUpdateBatch(candidatePhotoPartitionTemp);
					}
				} catch (Exception exception) {
					logger.error("## compressTencentCosPhotoAsync error", exception);
				}
				return candidatePhotoList; 
			}
		});
	}
	
	
	private void updateKwTask(String taskId, String projectId) {
		iTaskService.lambdaUpdate()
		.eq(Task::getId, taskId)
		.set(Task::getTaskBmId, projectId)
		.update();
	}


	/**
	 * 删除原来的绑定数据
	 * @param taskId
	 */
	private void removeBindData(String taskId) {
		//删除kw_task_candidate_area表老数据
		iTaskCandidateAreaService.lambdaUpdate()
			.eq(TaskCandidateArea::getTaskId, taskId)
			.eq(TaskCandidateArea::getDelFlag, false)
			.set(TaskCandidateArea::getDelFlag, true)
			.update();

		//删除kw_subject表老数据
		iSubjectService.lambdaUpdate()
			.eq(Subject::getTaskId, taskId)
			.eq(Subject::getDelFlag, false)
			.set(Subject::getDelFlag, true)
			.update();
		//删除kw_candidate表老数据
		iCandidateService.lambdaUpdate()
			.eq(Candidate::getTaskId, taskId)
			.eq(Candidate::getDelFlag, false)
			.set(Candidate::getDelFlag, true)
			.update();
		
		//删除kw_candidate_subject表老数据
		iCandidateSubjectService.lambdaUpdate()
			.eq(CandidateSubject::getTaskId, taskId)
			.eq(CandidateSubject::getDelFlag, false)
			.set(CandidateSubject::getDelFlag, true)
			.update();
		
		//删除kw_candidate_subject表老数据
		iCandidatePhotoService.lambdaUpdate()
			.eq(CandidatePhoto::getTaskId, taskId)
			.eq(CandidatePhoto::getDelFlag, false)
			.set(CandidatePhoto::getDelFlag, true)
			.update();
		
		// 删除kw_candidate_info表老数据
		iCandidateInfoService.lambdaUpdate()
				.eq(CandidateInfo::getTaskId, taskId)
				.remove();
		
		// 删除cj_project_collect_info表数据
		iProjectCollectInfoService.removeByProjectId(taskId);
		// 删除cj_project_collect_info_option表数据
		iProjectCollectInfoOptionService.removeByProjectId(taskId);
		// 删除cj_project_image_standard表数据
		iProjectImageStandardService.removeByProjectId(taskId);
	}

}
